/*
**  File: AquaFuncts_io.c
**
**  This file is part of the AQUA program suite, which is being
**  developed in the NMR Spectroscopy Department, Bijvoet Center for 
**  Biomolecular Research, Utrecht, the Netherlands and the BioMagResBank, 
**  University of Wisconsin-Madison, USA.

**
**  AUTHOR(S) : Ton Rullmann, Jurgen Doreleijers
**  VERSION   : 1.4.0, 3.2
**  DATE      : Jul 18, 1997, January, 2001
**
**  Master file for io to/from different non-Aqua formats.
**  The flow scheme is as follows:
**
**  ReadMenu 
**      ReadAquaSet                } routine in AquaStrucset.c
**    -or-
**      ReadAll                    } routine in this file
**          AtomCount              } routine in this file
**                  AtomCount_pdb
**                  AtomCount_pdbmr
**          ReadMolCoordData       } routine in this file
**              #ifdef CVALL
**                  ReadDummy_cv
**                -or-
**                  ReadFil_cv
**                      Alloc_cv
**                      init_cv_   }
**                      rdpdb_     } Fortran routines from cv_subs.f
**                      close_cv_  }
**              #else
**                  ReadFil_cv_biosym
**                      Alloc_cv
**                      ReadHeader_biosym
**                      ...
**                -or-
**                  ReadFil_cv_pdb
**                      Alloc_cv
**                      ReadHeader_pdb
**                      ...
**                -or-
**                  ReadFil_cv_pdbmr
**                      Alloc_cv
**                      ReadHeader_pdbmr
**                      ...
**                -or-
**                  ReadDummy_cv
**              #endif
**              ToAqua_cv
**          Free_cv
**
**  Separate files for each format (biosym, pdb etc.) are #included at the bottom.
**  Routines with names ending in _cv are in file AquaFuncts_cv.c.
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "Compiler.h"
#include "General.h"

#include "AquaTypes.h"

/****************  function prototypes  ****************/

#include "AquaFuncts.h"
#include "AquaFuncts_cv.h"
#include "AquaStrucset.h"
#include "MenuFuncts.h"
#include "Functs.h"

#include "AquaFuncts_io.h"


/****************  globals  ****************/

extern Boolean  iaf;                        /* import from Functs */
extern Card     msg_string;                 /* import from Functs */
extern int      terseness;                  /* import from Functs */

extern Boolean alloc_cv;                    /*       ...     */
extern char    *header;                     /*      ...      */
extern float   *x, *y, *z;                  /*  import from  */
extern int     *atono, *resno;              /* AquaFuncts_cv */
extern char    *atonam, *btonam, *resnam;   /*      ...      */
extern char    *chain, *insert, *atoel;     /*      ...      */

#define MAXHEADER     10                    /* should be same as in AquaFuncts_cv */
#define size_HEADER   size_LINE


/* BEGIN_EXTH */

/****************  ReadMenu  ****************/
/*
**  Handle the Read menu: list (i.e. read file names from file-list),  
**  aqua, pdb, biosym etc.
*/

Boolean ReadMenu( Strucset *set, Boolean onlyone )
{
    char     *crdinp, *fct_name = "ReadMenu";
    int      item;
    Filnam   list_filnam;
    FILE     *list_fp = NULL;
    Filtyp   type;
    Boolean  ok = false;
    Menu     *oldmenu;
    
    static MenuItem menulist[] =
    {
        { crd_list,   "list",    none, on },
        { crd_aqua,   "aqua",    none, on }, 
        { crd_dummy,  "dummy",   none, on }, 
        { crd_pdb,    "pdb",     none, on }, 
        { crd_pdbn,   "pdbn",    none, on }, 
        { crd_pdbx,   "pdbx",    none, on }, 
        { crd_pdbm,   "pdbm",    none, on }, 
        { crd_pdbmr,  "pdbmr",   none, on }, 
        { crd_biosym, "biosym",  none, on }, 
        { item_END,   "end",     none, on } 
    };                                          /* same as in AquaWhat */
    static Menu menu =
    {
        "Read menu", "option", "Give option:",
        sizeof(menulist)/sizeof(MenuItem)
    };
    
/* what routines am i using? */

    sprintf( msg_string, "starting to read strucset <%s>", set->name );
    if ( terseness < 6 ) {
        STATUSm;
#ifdef CVALL
        STATUS( "using the routines from AquaFuncts_cv.c and cvall.f" );
#else
        STATUS( "using the routines from AquaFuncts_io.c" );
#endif
    }
/* save menu and setup new one */
    
    oldmenu = SetMenu( &menu, menulist );
    crdinp = GetOptionCVal( opt_crdinp );       /* use value of coordinp option */
                                                /* OK if option menu has not been swapped */

/* determine file type and possibly use list option */

    while ( true )
    {
	if ( EQ( crdinp, "none" ) )
	    item = ReadMenuItem();
	else
	    item = FindMenuItem( crdinp );
        switch ( item )
        {
            case crd_list:
                SetOneMenu( "Give name of list file:" );  /* menu change */
                MReadWord( list_filnam );
                if ( NOTOPENr( list_fp, list_filnam ) )
                {
                    printf( " * List-file <%s> could not be opened\n", list_filnam );
                    MError();
                    SetMenu( &menu, menulist );
                    break;
                }
                SetMenu( &menu, menulist );    /* undo the menu change */
                DisableMenuItem( crd_list );   /* force a file type choice in 2nd pass */
                DisableMenuItem( crd_aqua );   /* change program to allow multiple strucsets
                                                   to be read (put ReadAquaSet in loop, 
                                                   change ReadStrucset) */
                break;
            case crd_aqua:
                type = set_type;
                goto data;
            case crd_dummy:
                type = dummy_type;
                goto data;
            case crd_pdb:
                type = pdb_type;
                goto data;
            case crd_pdbn:
                type = pdbn_type;
                goto data;
            case crd_pdbx:
                type = pdbx_type;
                goto data;
            case crd_pdbm:
                type = pdbm_type;
                goto data;
            case crd_pdbmr:
                type = pdbmr_type;
                goto data;
            case crd_biosym:
                type = biosym_type;
                goto data;
            case item_END:
            case item_NULL:
                goto end;
            default:
                ProcessMenuError( menu_fatal );
                break;
        }    
    }

data:
    if ( type == set_type )                  /* process aqua strucset file */
	ok = ReadAquaSet( set, onlyone ? 1 : -1 );
    else                                     /* process other files */
	ok = ReadAll( set, type, list_fp, onlyone );

end:
    if ( terseness < 6 ) {
        printf( "\nThe set <%s> now contains %i structure(s)\n", 
                set->name, set->struc_count );
    }
    EnableMenuItem( crd_list );
    EnableMenuItem( crd_aqua );
    ResetMenu( oldmenu );                        /* reinstall the saved menu */
    return( ok );
}

/****************  WriteMenu  ****************/
/*
**  Handle the Write menu.
*/

Boolean WriteMenu( Strucset *set, const Boolean toscreen )
{
    char     *crdout, *fct_name = "WriteMenu";
    int      item;
    Filtyp   type;
    Boolean  ok = false;
    Menu     *oldmenu;
    
    static MenuItem menulist[] =
    {
        { crd_aqua,    "aqua",    none, on }, 
        { crd_pdb,     "pdb",     none, on }, 
        { crd_star,    "star",    none, on }, 
        { crd_pdbn,    "pdbn",    none, off }, 
        { crd_pdbx,    "pdbx",    none, off }, 
        { crd_pdbm,    "pdbm",    none, off }, 
        { crd_biosym,  "biosym",  none, off }, 
        { item_END,    "end",     none, on } 
    };                                          /* same as in AquaWhat */
    static Menu menu =
    {
        "Write menu", "option", "Give option:",
        sizeof(menulist)/sizeof(MenuItem)
    };
    
/* initial integrity check */

    sprintf( msg_string, "starting to write strucset <%s>", set->name );
    if ( terseness < 6 ) {
        STATUSm;
    }
    
    if ( EMPTYSET( *set ) )
    {
	printf( "the strucset <%s> is empty\n", set->name );
        return( false );
    }

/* save menu and setup new one */
    
    oldmenu = SetMenu( &menu, menulist );
    crdout = GetOptionCVal( opt_crdout );       /* use value of coordout option */
                                                /* OK if option menu has not been swapped */

/* determine file type and possibly use list option */

    while ( true )
    {
	if ( EQ( crdout, "none" ) )
	    item = ReadMenuItem();
	else
	    item = FindMenuItem( crdout );
        switch ( item )
        {
            case crd_aqua:
                type = set_type;
                goto data;
            case crd_pdb:
                type = pdb_type;
                goto data;
            case crd_star:
                type = star_type;
                goto data;
            case crd_pdbn:
                type = pdbn_type;
                goto data;
            case crd_pdbx:
                type = pdbx_type;
                goto data;
            case crd_pdbm:
                type = pdbm_type;
                goto data;
            case crd_biosym:
                type = biosym_type;
                goto data;
            case item_END:
            case item_NULL:
                goto end;
            default:
                ProcessMenuError( menu_fatal );
                break;
        }    
    }

data:
    if ( type == set_type )                  /* process aqua strucset file */
	ok = WriteAquaSet( set, toscreen, false );
    else                                     /* process other files */
	ok = WriteAll( set, type, toscreen );

end:
    if ( !ok )
	puts( " * Data could not be written" );
    ResetMenu( oldmenu );                        /* reinstall the saved menu */
    return( ok );
}

/****************  WriteAll  ****************/
/*
**  Write a molecular coordinate data file. Currently all models are written.
*/

Boolean WriteAll( Strucset *set, const Filtyp type, const Boolean toscreen )
{
    int      model = 0;
    Boolean  wrmodel = false;
    Boolean  done = false, ok = false;
    Filnam   data_filnam;
    FILE     *data_fp = NULL;
    Menu     *oldmenu;

    oldmenu = SetOneMenu( "Give name of data file (or - to end):" );

    if ( toscreen )
    {
	data_fp = stdout;
	done = true;
    }

/* open the data file */

    while ( !done )
    {
	MReadWord( data_filnam );
        if ( *data_filnam == '-' || strlen( data_filnam ) == 0 )
	    goto end;                       /* no processing */

	if ( ( data_fp = fopen( data_filnam, "w" ) ) == NULL )
	{
	    printf( " * Data-file <%s> could not be opened\n", data_filnam );
	    MError();
	}
	else
	    done = true;
    }

/* write the data */

    switch ( type )
    {
	case pdb_type:
	    ok = Write_pdb( data_fp, set, model, wrmodel );
	    break;
	case star_type:
	    ok = Write_star( data_fp, set, model, wrmodel );
	    break;
	default:
            puts( " * Unknown file type in WriteAll" );
            exit( 1 );
    }

end:
    if ( data_fp != stdout )
	fclose( data_fp );
    ResetMenu( oldmenu );                    /* reinstall the saved menu */
    return( ok );
}

/****************  ReadAll  ****************/
/*
**  Process one or more molecular coordinate data files, 
**  in a loop that first reads the file name.
*/

Boolean ReadAll( Strucset *set, const Filtyp type, FILE *list_fp, Boolean onlyone )
{
    Filnam   data_filnam;
    FILE     *data_fp = NULL;
    int      atom_count = 0;
    Boolean  use_list_fp;
    Boolean  eof = false, ok = false;
    Menu     *oldmenu;
    

#ifdef FORTRAN_IO
    InitFortranIO();
#endif

    use_list_fp = ( list_fp != NULL );

/* read data-file names until eof or until a - is read
    and process the files */

    if ( type == dummy_type )
        oldmenu = SetOneMenu( "Give dummy file name (any text), or - to end:" );
    else 
        oldmenu = SetOneMenu( "Give name of data file (or - to end):" );
    
    do
    {
        if ( use_list_fp )
	{
            if ( !ReadWord( data_filnam, size_FILNAM, false, list_fp ) )
		break;
	}
        else
            MReadWord( data_filnam );
        if ( *data_filnam == '-' || strlen( data_filnam ) == 0 )
        {
            eof = true;
            break;                           /* end reading when a - is input */
        }

        if ( type == dummy_type )            /* dummy data */
            strcpy( data_filnam, "dummy" );
        else
	{
	    if ( *data_filnam == '%' && !use_list_fp )
	    {                                /* treat data file as list file */
                if ( NOTOPENr( list_fp, data_filnam+1 ) )
                {
                    printf( " * List-file <%s> could not be opened\n", data_filnam+1 );
		    MError();
		    goto end;
		}
		use_list_fp = true;
		continue;
	    }
/* open the data file */
            if ( NOTOPENr( data_fp, data_filnam ) )
            {
                printf( " * Data-file <%s> could not be opened\n", data_filnam );
                MError();
		goto end;
            }
	}
        if ( EMPTYSET( *set ) )
        {
            atom_count = AtomCount( data_fp, type );
	    if ( atom_count <= 0 )
		break;
            if ( terseness < 6 ) {
                printf( "Will read %i atoms from each file\n", atom_count );
            }
        }
        if ( terseness < 6 ) {
	    printf( "\nNext file <%s>:\n", data_filnam );
        }
        ok = ReadMolCoordData( set, data_fp, data_filnam, type, atom_count, onlyone );
	if ( !ok )
	    break;
	if ( type == dummy_type )
            set->type = dummy_str_data;
        else
            set->type = orig_str_data;
        if ( IsEmptyStr( set->ident ) )
            DefaultStrucsetIdent( set );
    }
    while ( !eof && !onlyone );

/* reached eof: no more reading */

    Free_cv();                               /* free memory again */

    if ( use_list_fp )
        fclose( list_fp );
end:
    ResetMenu( oldmenu );                    /* reinstall the saved menu */
    return( ok );
}

/****************  ReadMolCoordData  ****************/
/*
**  Read one or more structures from one non-aqua molecular 
**  coordinate data file.
*/

Boolean ReadMolCoordData( Strucset *set, FILE *fp, Filnam filnam, 
                          const Filtyp type, const int atom_count, 
			  Boolean onlyone )
{
    static int   struc_count = 0;
    int          fil_struc_num = 0;
    int          nerr = 0;
    Status       stat = status_ok;
    Boolean      done = false, store_int = false, ok = false;

    while ( !done )
    {

/* attempt to read one (more) structure */    

	store_int = false;

#ifdef CVALL
	if ( type == dummy_type )
	{
	    stat = ReadDummy_cv( atom_count, &fil_struc_num );
	    done = true;
	}
	else
	{
	    if ( fp )
		fclose( fp );
	    stat = ReadFil_cv( filnam, type, atom_count, &fil_struc_num, &nerr );
	    done = true;                 /* handle only 1 structure for now */
	}
#else
	switch ( type )
	{
	    case biosym_type:
		stat = ReadFil_cv_biosym( fp, type, atom_count, &fil_struc_num, &nerr );
		break;
	    case pdb_type:
	    case pdbn_type:
	    case pdbx_type:
	    case pdbm_type:
		stat = ReadFil_cv_pdb( fp, type, atom_count, &fil_struc_num, &nerr );
		break;
	    case pdbmr_type:
		store_int = true;
		stat = ReadFil_cv_pdbmr( fp, type, atom_count, &fil_struc_num, &nerr );
		break;
	    default:
		if ( type != dummy_type )
		{
		    printf( "Reading of data-file not yet implemented - set up dummy data instead\n" );
		    fclose( fp );
		}
		stat = ReadDummy_cv( atom_count, &fil_struc_num );
		done = true;
	}
#endif
	if ( stat == status_ok ) 
	{
            if ( terseness < 6 ) {
	        printf( "structure %i read\n", fil_struc_num );
            }
	    ToAqua_cv( set, filnam, type, atom_count, fil_struc_num, store_int );
	    ok = true;
	    done = onlyone;
	}
	else
	{
	    done = true;
	    if ( stat != end_of_data )
	    {
		printf( " * Error occurred after reading %i atoms of structure # %i of file\n", 
		nerr, fil_struc_num );
		if ( !iaf )
		    exit( 1 );
	    }
	}
    }

    if ( fp )
	fclose( fp );
    if ( terseness < 6 ) {
        printf( "\nRead %i structure(s) from file <%s>\n", 
            set->struc_count - struc_count, filnam );
    }
    struc_count = set->struc_count;
    return( ok );
}

/****************  AtomCount  ****************/
/*
**  Determine the number of atoms from a data file.
*/

int AtomCount( FILE *fp, const Filtyp type )
{
    int    count;
    Menu   *oldmenu;
    char   text[10];
    
    switch ( type )
    {
        case pdb_type:
        case pdbn_type:
        case pdbx_type:
        case pdbm_type:
	    count = AtomCount_pdb( fp );
	    break;
        case pdbmr_type:
	    count = AtomCount_pdbmr( fp );
	    break;
        case biosym_type:
	    count = AtomCount_biosym( fp );
	    break;
        case dummy_type:
            oldmenu = SetOneMenu( "Give number of atoms:" );
            MReadWord( text );
            sscanf( text, "%i", &count );
	    ResetMenu( oldmenu );
            break;
        default:
            puts( " * Unknown file type in AtomCount" );
            exit( 1 );
    }
    
    if ( count <= 0 )
    {
        printf( " * Number of atoms not valid: %i\n", count );
        if ( !iaf )
	    exit( 1 );
    }
    if ( type != dummy_type )
        rewind( fp );
    return( count );
}


/* END_EXTH */


/****************  and now... the source files  ****************/

#include "AquaFuncts_biosym.c"
#include "AquaFuncts_xplor.c"
#include "AquaFuncts_diana.c"
#include "AquaFuncts_pdb.c"
#include "AquaFuncts_pdbmr.c"
#include "AquaFuncts_nmrstar.c"
